package com.xplay.xpocker.dvo;

import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.xplay.xpocker.constant.ConstantDict;
import com.xplay.xpocker.entity.GameRuMahjongFraction;
import com.xplay.xpocker.entity.GameRuMahjongUser;
import com.xplay.xpocker.entity.GameRuMahjongOpenDeal;
import com.xplay.xpocker.room.mahjong.dto.MahjongActionEnum;
import com.xplay.xpocker.room.mahjong.dto.MahjongMessage;
import com.xplay.xpocker.util.CardUtil;
import com.xplay.xpocker.util.ObjectUtils;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

@Data
public class GameRuMahjongUserState extends GameRuMahjongUser {
    // 碰杠的数据
    private List<GameRuMahjongOpenDeal> openDeal;
    private String username;
    private String portraitUrl;
    private int handCardCount;
    private Integer seq;
    // 要对拿入拿出的数据脱敏，需要使用两个标记符判断用户是否拿入拿出
    // 是否拿出
    private boolean swapOutStatus;
    // 是否拿进
    private boolean swapInStatus;
    private boolean onHook;
    private boolean online;

    private List<GameRuMahjongFraction> fractions;

    public void addOpenDeal(GameRuMahjongOpenDeal gameRuUserOpenDeal) {
        if (openDeal == null) {
            this.openDeal = new ArrayList<>();
        }
        openDeal.add(gameRuUserOpenDeal);
    }

    public void addFraction(GameRuMahjongFraction fraction) {
        if (fractions == null) {
            this.fractions = new ArrayList<>();
        }
        fractions.add(fraction);
    }

    /**
     * 增加出牌数据
     *
     * @param card
     * @return
     */
    public String addExportCard(Integer card) {
        String exportCards = getExportCards();
        if (exportCards == null || exportCards.equals("")) {
            return card.toString();
        } else {
            return exportCards + ConstantDict.Separator.comma + card.toString();
        }
    }

    public String deleteLastCard(String cards) {
        List<Integer> allCard = CardUtil.buildCardList(cards);
        allCard.remove(allCard.size() - 1);
        return CardUtil.joinCard(allCard);
    }

    public List<Integer> allHandCards() {
        if (ObjectUtils.isEmpty(this.getHandCards())) {
            return null;
        }
        List<Integer> result = Arrays.stream(this.getHandCards().split(ConstantDict.Separator.comma)).map(Integer::valueOf).collect(Collectors.toList());
        if (getTouchCard() != null) {
            result.add(getTouchCard());
        }
        Collections.sort(result);
        return result;
    }

    public String allHandCardsStr() {
        return allHandCards().stream().map(String::valueOf).collect(Collectors.joining(ConstantDict.Separator.comma));
    }

    /**
     * 移出手牌数据
     *
     * @param cards
     * @return
     */

    public void removeCard(Integer... cards) {
        if (cards == null) {
            return;
        }
        List<Integer> removeCards = Arrays.stream(cards).collect(Collectors.toList());
        removeCard(removeCards);
    }

    public void removeCard(List<Integer> cards) {
        List<Integer> handCards = allHandCards();
        Map<Integer, Long> removeCardMap = cards.stream()
                .collect(Collectors.groupingBy(num -> num, Collectors.counting()));
        for (Iterator<Integer> iterator = handCards.iterator(); iterator.hasNext(); ) {
            Integer element = iterator.next();
            if (removeCardMap.containsKey(element)) {
                Long count = removeCardMap.get(element);
                // 如果集合2中该元素还有剩余要移除的实例
                if (count > 0) {
                    iterator.remove();
                    removeCardMap.put(element, count - 1);
                }
            }
        }
        //重新初始化用户手牌
        reitUserTouchCard(handCards);
    }

    public void addCardList(List<Integer> card) {
        List<Integer> result = allHandCards();
        result.addAll(card);
        //重新初始化用户手牌
        reitUserTouchCard(result);
    }

    public void removeCardAll(Integer card) {
        List<Integer> result = allHandCards();
        List<Integer> newCardArray = result.stream().filter(number -> !number.equals(card)).collect(Collectors.toList());
        //如果移出后摸得那张牌还在手牌中  从手牌中移出掉摸得那张牌
        reitUserTouchCard(newCardArray);
    }

    private void reitUserTouchCard(List<Integer> userAllCard) {
        if (userAllCard.size() % 3 == 2 && getTouchCard() != null && userAllCard.contains(getTouchCard())) {
            userAllCard.remove(getTouchCard());
        } else if (userAllCard.size() % 3 == 2) {
            // 将最后一个元素设置成为手牌
            setTouchCard(userAllCard.get(userAllCard.size() - 1));
            //移除掉手牌 里面最后一个元素
            userAllCard.remove(userAllCard.size() - 1);
        } else {
            setTouchCard(null);
        }
        this.setHandCards(StringUtils.join(userAllCard, ConstantDict.Separator.comma));
    }

    public GameRuMahjongOpenDeal checkOpenDealBar(Integer targetValue) {
        if (ObjectUtils.isEmpty(this.getOpenDeal())) {
            return null;
        }
        for (GameRuMahjongOpenDeal deal : getOpenDeal()) {
            if (deal.getCard().equals(targetValue) && deal.getType() != null && deal.getType().equals(1)) {
                return deal;
            }
        }
        return null;
    }

    public GameRuMahjongOpenDeal getOpenDealByCard(Integer targetValue) {
        if (ObjectUtils.isEmpty(this.getOpenDeal())) {
            return new GameRuMahjongOpenDeal();
        }
        Optional<GameRuMahjongOpenDeal> deal = getOpenDeal().stream().filter(item -> item.getCard().equals(targetValue)).findAny();
        return deal.orElse(new GameRuMahjongOpenDeal());
    }

    /**
     * 明杠判断
     *
     * @return
     */
    public boolean checkUserMingBar() {
        String completedHistory = getCompletedHistory();
        if (completedHistory == null) {
            return false;
        }
        return completedHistory.endsWith(MahjongActionEnum.BAR_CARD.getAction());
    }

    /**
     * 杠上开炮判断
     *
     * @return
     */
    public boolean checkBarShooting() {
        String completedHistory = getCompletedHistory();
        if (completedHistory == null) {
            return false;
        }
        return completedHistory.endsWith(String.format("%s,%s",
                MahjongActionEnum.BAR_CARD.getAction(), MahjongActionEnum.EXPORT_CARD.getAction()));
    }

    /**
     * 杠上开花判断
     *
     * @return
     */
    public boolean checkBarBlossom() {
        String completedHistory = getCompletedHistory();
        if (completedHistory == null) {
            return false;
        }
        return completedHistory.endsWith(String.format("%s,%s",
                MahjongActionEnum.BAR_CARD.getAction(), MahjongActionEnum.HU.getAction()));
    }

    /**
     * 将用户的历史行为记录起来
     *
     * @param action
     */

    public void appendCompletedHistory(String action) {
        String completedHistory = getCompletedHistory();
        if (completedHistory == null) {
            setCompletedHistory(action);
        } else {
            setCompletedHistory(completedHistory + ConstantDict.Separator.comma + action);
        }
    }

    /**
     * 判断某张牌 在手牌上的数量
     * ==2  碰牌
     * ==3  杠牌
     *
     * @param targetValue
     * @return
     */

    public int checkTally(Integer targetValue) {
        List<Integer> result = allHandCards();
        if (ObjectUtils.isEmpty(result)) {
            return 0;
        }
        Collections.sort(result);
        return countOccurrences(result, targetValue);
    }

    public int countOccurrences(List<Integer> array, int targetValue) {
        int count = 0;
        for (int i = 0; i < array.size(); i++) {
            if (array.get(i) == targetValue) {
                count++;
            }
        }
        return count;
    }

    /**
     * 因为自己只能看自己的牌，所以这里需要返回一个总数
     * 当前玩家看其余玩家只能看到总数
     *
     * @return
     */

    public int getHandCardCount() {
        if (this.handCardCount > 0) {
            return this.handCardCount;
        }
        if (ObjectUtils.isEmpty(this.getHandCards())) {
            return 0;
        }
        int cardCount = this.getHandCards().split(ConstantDict.Separator.comma).length;
        if (getTouchCard() != null) {
            cardCount++;
        }
        return cardCount;
    }

    /**
     * 判断用户是否同时存在
     *
     * @param actionEnums
     * @return
     */

    public boolean checkUserAllExistAction(MahjongActionEnum... actionEnums) {
        if (ObjectUtils.isEmpty(this.getWaitCompleted())) {
            return false;
        }
        if (actionEnums.length == 0) {
            return false;
        }
        HashSet<String> checkActions = Arrays.stream(actionEnums).map(MahjongActionEnum::getAction).collect(Collectors.toCollection(HashSet::new));
        return new HashSet<>(Arrays.stream(this.getWaitCompleted().split(ConstantDict.Separator.comma)).collect(Collectors.toList())).containsAll(checkActions);
    }

    /**
     * 存在一个返回ture
     *
     * @param actionEnums
     * @return
     */

    public boolean checkUserExistAction(MahjongActionEnum... actionEnums) {
        if (ObjectUtils.isEmpty(this.getWaitCompleted())) {
            return false;
        }
        if (actionEnums.length == 0) {
            return false;
        }
        HashSet<String> checkActions = Arrays.stream(actionEnums).map(MahjongActionEnum::getAction).collect(Collectors.toCollection(HashSet::new));
        return Arrays.stream(this.getWaitCompleted().split(ConstantDict.Separator.comma)).anyMatch(checkActions::contains);
    }

    /**
     * 移出用户的事件
     *
     * @param actionEnums
     * @return
     */

    public boolean removeUserAction(MahjongActionEnum... actionEnums) {
        if (ObjectUtils.isEmpty(this.getWaitCompleted())) {
            return true;
        }
        if (actionEnums.length == 0) {
            return true;
        }
        List<String> removeActions = Arrays.stream(actionEnums).map(MahjongActionEnum::getAction).collect(Collectors.toList());
        List<String> userActions = Arrays.stream(this.getWaitCompleted().split(ConstantDict.Separator.comma)).collect(Collectors.toList());
        userActions.removeAll(removeActions);
        this.setWaitCompleted(StringUtils.join(userActions, ConstantDict.Separator.comma));
        return true;
    }

    /**
     * 判断用户是否只有一个行为
     *
     * @param actionEnum
     * @return
     */

    public boolean checkUserSingWaitCompleted(MahjongActionEnum actionEnum) {
        if (ObjectUtils.isEmpty(this.getWaitCompleted())) {
            return false;
        }
        return this.getWaitCompleted().equals(actionEnum.getAction());
    }

    public void saveNextAction(MahjongActionEnum action, MahjongMessage message) {
        setCompleted(action.getAction());
        setCompletedData(message);
    }

    public void cleanNextAction() {
        setCompletedData(null);
    }
}
